﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using System.Linq.Expressions;
using System.Data;
using System.Data.Objects.DataClasses;
using System.Data.Common;
using Rocket.Windows.Framework;
using Rocket.Core;

namespace Rocket.Data
{
    public sealed class RocketRepository<T> : IRepository<T>
        where T : EntityObject
    {
        static readonly RocketRepository<T> instance
            = new RocketRepository<T>(new Raptor_CoreEntities());
        private static readonly Object _lockObject = new Object();
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static RocketRepository()
        {
            if (_lockObject == null)
                _lockObject = new Object();
        }

        public static RocketRepository<T> Instance
        {
            get
            {
                //return new RaptorRepository<T>(new RaptorCoreEntities());
                return instance;
            }
        }

        RocketRepository(ObjectContext repositoryContext)
        {
            _repositoryContext = repositoryContext ?? new Raptor_CoreEntities();
            _objectSet = _repositoryContext.CreateObjectSet<T>();
        }

        public IRepository<T> GetRepository()
        {
            return Instance;
        }

        private static ObjectContext _repositoryContext;
        private ObjectSet<T> _objectSet;
        public ObjectSet<T> ObjectSet
        {
            get
            {
                return _objectSet;
            }
        }

        #region IRepository Members

        public void Add(T entity)
        {
            lock (_lockObject)
            {
                this._objectSet.AddObject(entity);
                _repositoryContext.SaveChanges();
                _repositoryContext.AcceptAllChanges();
            }
        }

        public void Update(T entity)
        {
            lock (_lockObject)
            {
                _repositoryContext.ApplyOriginalValues(((IEntityWithKey)entity)
                    .EntityKey.EntitySetName, entity);
                _repositoryContext.Refresh(RefreshMode.ClientWins, _objectSet);
                _repositoryContext.SaveChanges();
                _repositoryContext.AcceptAllChanges();
            }
        }

        public void Delete(T entity)
        {
            lock (_lockObject)
            {
                this._objectSet.DeleteObject(entity);
                _repositoryContext.Refresh(RefreshMode.ClientWins, _objectSet);
                _repositoryContext.SaveChanges();
                _repositoryContext.AcceptAllChanges();
            }
        }

        public void DeleteAll()
        {
            _repositoryContext
                .ExecuteStoreCommand("DELETE " + _objectSet.EntitySet.ElementType.Name);
        }

        public IList<T> GetAll()
        {
            lock (_lockObject)
            {
                return this._objectSet.ToList<T>();
            }
        }

        public IList<T> GetAll(Expression<Func<T, bool>> whereCondition)
        {
            lock (_lockObject)
            {
                return this._objectSet.Where(whereCondition).ToList<T>();
            }
        }

        public T GetSingle(Expression<Func<T, bool>> whereCondition)
        {
            lock (_lockObject)
            {
                return this._objectSet.Where(whereCondition).FirstOrDefault<T>();
            }
        }

        public IQueryable<T> GetQueryable()
        {
            lock (_lockObject)
            {
                return this._objectSet.AsQueryable<T>();
            }
        }

        public long Count()
        {
            return this._objectSet.LongCount<T>();
        }

        public long Count(Expression<Func<T, bool>> whereCondition)
        {
            return this._objectSet.Where(whereCondition).LongCount<T>();
        }

        #endregion
    }
}
